﻿using System.Collections.Generic;
using System.Web.Mvc;
using TeamsPortal.ServiceClient;
using TeamsPortal.Validation;
using TeamsPortal.Web.Controllers.Filters;
using TeamsPortal.Web.Controllers.Helpers;
using TeamsPortal.Web.Extensions;
using TeamsPortal.DataAccess;

namespace TeamsPortal.Web.Controllers
{
	public class MessagesController : BaseController
	{
        private ITopicsServiceClient _topicServiceClient;
        private IMessagesServiceClient _messageServiceClient;
        private ITopicsSubscriptionsServiceClient _subscriptionServiceClient;

        public MessagesController(ITopicsServiceClient topicServiceClient, IMessagesServiceClient messageServiceClient, ITopicsSubscriptionsServiceClient subscriptionServiceClient)
        {
            _topicServiceClient = topicServiceClient;
            _messageServiceClient = messageServiceClient;
            _subscriptionServiceClient = subscriptionServiceClient;
        }

		#region Add
		/// <summary>
		/// Loads the "reply to a topic" form
		/// </summary>
		/// <param name="id">thread id</param>
		/// <param name="name">thread short name</param>
		/// <param name="msg">Message id of the message being quoted.</param>
		[HttpGet]
		[RequireAuthorization]
		[PreventFlood]
		public ActionResult Add(int id, string name, int? msg)
		{
			var message = new Message();
            message.Topic = _topicServiceClient.Get(id, name);
			#region Check topic
			if (message.Topic == null)
			{
				return ResultHelper.NotFoundResult(this);
			}
			if (!message.Topic.HasPostAccess(Role))
			{
				return ResultHelper.ForbiddenResult(this);
			}
			if (message.Topic.IsClosed)
			{
				return ResultHelper.ForbiddenResult(this);
			} 
			#endregion
			if (msg != null)
			{
				message.InReplyOf = new Message(msg.Value);
			}

            ViewData["notify"] = SubscriptionHelper.IsUserSubscribed(id, User.Id, Config, _subscriptionServiceClient);

			return View("Edit", message);
		}

		/// <summary>
		/// Saves the message or Loads the reply form to allow the user to clear error messages
		/// </summary>
		/// <param name="id">thread id</param>
		/// <param name="msg">Message id of the message being quoted.</param>
		[HttpPost]
		[RequireAuthorization]
		[ValidateInput(false)]
		[PreventFlood(SuccessResultType = typeof(RedirectToRouteResult))]
		public ActionResult Add([Bind(Prefix = "", Exclude = "Id")] Message message, int id, string name, string forum, int? msg, bool notify, string email)
		{
            message.Topic = _topicServiceClient.Get(id, name);
			#region Check topic
			if (message.Topic == null)
			{
				return ResultHelper.NotFoundResult(this);
			}
			if (!message.Topic.HasPostAccess(Role))
			{
				return ResultHelper.ForbiddenResult(this);
			}
			if (message.Topic.IsClosed)
			{
				return ResultHelper.ForbiddenResult(this);
			}
			#endregion
			try
			{
				SubscriptionHelper.SetNotificationEmail(notify, email, Session, Config, UsersServiceClient);
                SubscriptionHelper.Manage(notify, message.Topic.Id, User.Id, User.Guid, Config, _subscriptionServiceClient);

				if (message.Body != null)
				{
					message.Body = message.Body.SafeHtml().ReplaceValues();
				}
				message.User = Session.User.ToUser();
				if (msg != null)
				{
					message.InReplyOf = new Message(msg.Value);
				}
				if (ModelState.IsValid)
				{
                    _messageServiceClient.Add(message, Request.UserHostAddress);
                    SubscriptionHelper.SendNotifications(this, message.Topic, Config, _subscriptionServiceClient);
					//Redirect to the message posted
                    int pageNumber = Pager.CalculatePageNumber(Config.UI.MessagesPerPage, message.Id);

                    return new RedirectToRouteExtraResult(
                        new { action = "Detail", controller = "Topics", id = id, name = name, forum = forum, page = pageNumber },
                        "#msg" + message.Id);
				}
			}
			catch (ValidationException ex)
			{
				this.AddErrors(ModelState, ex);
			}
			return View("Edit", message);
		}
		#endregion

        #region Edit
        /// <param name="forum">Forum's short name</param>
        /// <param name="name">Topic's short name</param>
        /// <param name="id">Topic's id</param>
        /// <param name="msgId">Message id</param>
        /// <returns></returns>
        [HttpGet]
        [RequireAuthorization]
        public ActionResult Edit(string forum, string name, int id, int msgId)
        {
            Message message = _messageServiceClient.Get(msgId, id);
            if (message == null)
            {
                return ResultHelper.NotFoundResult(this);
            }

            Topic topic = _topicServiceClient.Get(id, name);
            #region Check topic
            if (!topic.HasPostAccess(Role))
            {
                return ResultHelper.ForbiddenResult(this);
            }
            if (topic.IsClosed)
            {
                return ResultHelper.ForbiddenResult(this);
            }
            #endregion
            message.Topic = topic;

            if (_messageServiceClient.IsReplied(message.Id, id))
            {
                ViewBag.AlertMessage = "You can't edit a message if somebody already cited it.";
                return View("AlertMessage", message);
            }

            return View(message);
        }

        /// <param name="message"></param>
        /// <param name="id">Topic's id</param>
        /// <param name="name"></param>
        /// <param name="forum"></param>
        /// <param name="msgId"></param>
        /// <param name="notify"></param>
        /// <returns></returns>
        [HttpPost]
        [RequireAuthorization]
        [ValidateInput(false)]
        [ValidateAntiForgeryToken]
        public ActionResult Edit([Bind(Prefix = "", Exclude = "Id")] Message message, int id, string name, string forum, int msgId, bool notify)
        {
            Topic topic = _topicServiceClient.Get(id, name);
            #region Check topic
            if (!topic.HasPostAccess(Role))
            {
                return ResultHelper.ForbiddenResult(this);
            }
            if (topic.IsClosed)
            {
                return ResultHelper.ForbiddenResult(this);
            }
            #endregion
            message.Topic = topic;
            message.Id = msgId;

            Message oldMessage = _messageServiceClient.Get(msgId, id);
            if (!User.HasModeratorPriviledges && oldMessage.User.Id != User.Id)
            {
                return ResultHelper.ForbiddenResult(this);
            }

            try
            {
                SubscriptionHelper.Manage(notify, topic.Id, User.Id, User.Guid, Config, _subscriptionServiceClient);

                message.Body = message.Body.SafeHtml().ReplaceValues();
                _messageServiceClient.UpdateBody(message, User.Id);
            }
            catch (ValidationException ex)
            {
                AddErrors(ModelState, ex);
                return View(message);
            }

            int pageNumber = Pager.CalculatePageNumber(Config.UI.MessagesPerPage, message.Id);

            return new RedirectToRouteExtraResult(
                new { action = "Detail", controller = "Topics", id = id, name = name, forum = forum, page = pageNumber },
                "#msg" + message.Id);
        }
		
        #endregion

        #region Delete
        /// <summary>
		/// Removes a message
		/// </summary>
		/// <param name="mid">message id</param>
		/// <param name="id">topic id</param>
		[HttpPost]
		[RequireAuthorization(UserRole.Moderator, RefuseOnFail = true)]
		public ActionResult Delete(int mid, int id, string forum, string name)
		{
            _messageServiceClient.Delete(id, mid, this.User.Id);
			return Json(true);
		}
		#endregion

		#region Flag messages
		/// <summary>
		/// Marks a message as inapropriate
		/// </summary>
		/// <param name="mid">Message id</param>
		/// <param name="id">Topic id</param>
		[HttpPost]
		public ActionResult Flag(int mid, int id, string forum, string name)
		{
            bool flagged = _messageServiceClient.Flag(id, mid, Request.UserHostAddress);

			return Json(flagged);
		}
		#endregion

		#region List flagged messages
		/// <summary>
		/// Gets a list of flagged messages
		/// </summary>
		/// <returns></returns>
		[RequireAuthorization(UserRole.Moderator)]
		public ActionResult ListFlagged()
		{
            List<Topic> topics = _messageServiceClient.ListFlagged();
			return View(topics);
		}
		#endregion

		#region ClearFlags
		[HttpPost]
		[RequireAuthorization(UserRole.Moderator, RefuseOnFail = true)]
		public ActionResult ClearFlags(int mid, int id, string forum, string name)
		{
            bool cleared = _messageServiceClient.ClearFlags(id, mid);
			return Json(cleared);
		}
		#endregion
	}
}
